package com.hxrfid.common.utils;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.hxrfid.common.exception.ServiceException;

import java.util.Collection;
import java.util.Map;

/**
 * 断言<br>
 * 断言某些对象或值是否符合规定，否则抛出异常。经常用于做变量检查
 *
 * @author lsh
 */
public class Assert {

    /**
     * 断言是否为真，如果为 {@code false} 抛出异常
     * @param expression 布尔值
     * @param errorMsg 错误抛出异常附带的消息 {
     */
    public static void isTrue(boolean expression, String errorMsg) {
        if (!expression) {
            throw new ServiceException(errorMsg);
        }
    }

    /**
     * 断言是否为真，如果为 {@code false} 抛出异常
     * @param expression       布尔值
     * @param errorMsgTemplate 错误抛出异常附带的消息模板，变量用{}代替
     * @param params           参数列表 {
     */
    public static void isTrue(boolean expression, String errorMsgTemplate, Object... params) {
        isTrue(expression, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言是否为假，如果为 {@code true} 抛出异常
     * @param expression    布尔值
     * @param errorMsg 错误抛出异常附带的消息 {
     */
    public static void isFalse(boolean expression, String errorMsg) {
        if (expression) {
            throw new ServiceException(errorMsg);
        }
    }

    /**
     * 断言是否为假，如果为 {@code true} 抛出异常
     * @param expression       布尔值
     * @param errorMsgTemplate 错误抛出异常附带的消息模板，变量用{}代替
     * @param params           参数列表 {
     */
    public static void isFalse(boolean expression, String errorMsgTemplate, Object... params) {
        isFalse(expression, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言对象是否为{@code null} ，如果不为{@code null} 抛出异常
     * @param object        被检查的对象
     * @param errorMsg 错误抛出异常附带的消息
     */
    public static void isNull(Object object, String errorMsg) {
        if (null != object) {
            throw new ServiceException(errorMsg);
        }
    }

    /**
     * 断言对象是否为{@code null} ，如果不为{@code null} 抛出异常
     * @param object           被检查的对象
     * @param errorMsgTemplate 消息模板，变量使用{}表示
     * @param params           参数列表
     */
    public static void isNull(Object object, String errorMsgTemplate, Object... params) {
        isNull(object, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言对象是否不为{@code null} ，如果为{@code null} 抛出异常
     * @param object        被检查对象
     * @param errorMsg 错误抛出异常附带的消息
     */
    public static  void notNull(Object object, String errorMsg) {
        if (null == object) {
            throw new ServiceException(errorMsg);
        }
    }

    /**
     * 断言对象是否不为{@code null} ，如果为{@code null} 抛出异常 .
     * @param object           被检查对象
     * @param errorMsgTemplate 错误消息模板，变量使用{}表示
     * @param params           参数
     */
    public static void notNull(Object object, String errorMsgTemplate, Object... params) {
        notNull(object, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 检查给定字符串是否为空，为空抛出异常
     * @param text          被检查字符串
     * @param errorMsg 错误抛出异常附带的消息
     */
    public static void notEmpty(String text, String errorMsg) {
        if (StrUtil.isEmpty(text)) {
            throw new ServiceException(errorMsg);
        }
    }

    /**
     * 检查给定字符串是否为空，为空抛出异常
     * @param text             被检查字符串
     * @param errorMsgTemplate 错误消息模板，变量使用{}表示
     * @param params           参数
     */
    public static void notEmpty(String text, String errorMsgTemplate, Object... params) {
        notEmpty(text, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 检查给定字符串是否为空白（null、空串或只包含空白符），为空抛出异常。
     * @param text             被检查字符串
     * @param errorMsg 错误抛出异常附带的消息
     */
    public static void notBlank(String text, String errorMsg) {
        if (StringUtils.isBlank(text)) {
            throw new ServiceException(errorMsg);
        }
    }

    /**
     * 检查给定字符串是否为空白（null、空串或只包含空白符），为空抛出异常
     * @param text             被检查字符串
     * @param errorMsgTemplate 错误消息模板，变量使用{}表示
     * @param params           参数
     */
    public static void notBlank(String text, String errorMsgTemplate, Object... params) {
        notBlank(text, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言给定字符串是否不被另一个字符串包含（即是否为子串）
     * @param textToSearch  被搜索的字符串
     * @param substring     被检查的子串
     * @param errorMsg 错误抛出异常附带的消息
     */
    public static void notContain(CharSequence textToSearch, CharSequence substring, String errorMsg) {
        if (StrUtil.contains(textToSearch, substring)) {
            throw new ServiceException(errorMsg);
        }
    }

    /**
     * 断言给定字符串是否不被另一个字符串包含（即是否为子串）
     * @param textToSearch     被搜索的字符串
     * @param substring        被检查的子串
     * @param errorMsgTemplate 异常时的消息模板
     * @param params           参数列表
     */
    public static void notContain(String textToSearch, String substring, String errorMsgTemplate, Object... params) {
        notContain(textToSearch, substring, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言给定字符串是否不被另一个字符串包含（即是否为子串）
     * @param textToSearch 被搜索的字符串
     * @param substring    被检查的子串
     */
    public static void notContain(String textToSearch, String substring) {
        notContain(textToSearch, substring, "[Assertion failed] - this String argument must not contain the substring [{}]", substring);
    }

    /**
     * 断言给定数组是否包含元素，数组必须不为 {@code null} 且至少包含一个元素抛出异常
     * @param <T>           数组元素类型
     * @param array         被检查的数组
     * @param errorMsg 错误抛出异常附带的消息
     */
    public static <T> void notEmpty(T[] array, String errorMsg) {
        if (ArrayUtil.isEmpty(array)) {
            throw new ServiceException(errorMsg);
        }
    }

    /**
     * 断言给定数组是否包含元素，数组必须不为 {@code null} 且至少包含一个元素
     * @param <T>              数组元素类型
     * @param array            被检查的数组
     * @param errorMsgTemplate 异常时的消息模板
     * @param params           参数列表
     */
    public static <T> void notEmpty(T[] array, String errorMsgTemplate, Object... params) {
        notEmpty(array, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言给定集合非空
     * @param collection    被检查的集合
     * @param errorMsg 错误抛出异常附带的消息
     */
    public static void notEmpty(Collection<?> collection, String errorMsg) {
        if (CollUtil.isEmpty(collection)) {
            throw new ServiceException(errorMsg);
        }
    }

    /**
     * 断言给定集合非空
     * @param collection       被检查的集合
     * @param errorMsgTemplate 异常时的消息模板
     * @param params           参数列表
     */
    public static void notEmpty(Collection<?> collection, String errorMsgTemplate, Object... params) {
        notEmpty(collection, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言给定Map非空
     * @param <K> Key类型
     * @param <V> Value类型
     * @param <T> Map类型
     * @param map      被检查的Map
     * @param errorMsg 错误抛出异常附带的消息
     */
    public static <K, V, T extends Map<K, V>> void notEmpty(T map, String errorMsg) {
        if (MapUtil.isEmpty(map)) {
            throw new ServiceException(errorMsg);
        }
    }

    /**
     * 断言给定Map非空
     * @param <K> Key类型
     * @param <V> Value类型
     * @param <T> Map类型
     * @param map              被检查的Map
     * @param errorMsgTemplate 异常时的消息模板
     * @param params           参数列表
     */
    public static <K, V, T extends Map<K, V>> void notEmpty(T map, String errorMsgTemplate, Object... params) {
        notEmpty(map, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言给定对象是否是给定类的实例
     * @param <T>  被检查对象泛型类型
     * @param type 被检查对象匹配的类型
     * @param obj  被检查对象
     * @param errorMsg 错误抛出异常附带的消息
     */
    public static <T> void isInstanceOf(Class<?> type, T obj, String errorMsg) {
        isInstanceOf(type, obj, errorMsg, obj, type);
    }

    /**
     * 断言给定对象是否是给定类的实例
     * @param <T>              被检查对象泛型类型
     * @param type             被检查对象匹配的类型
     * @param obj              被检查对象
     * @param errorMsgTemplate 异常时的消息模板
     * @param params           参数列表
     */
    public static <T> void isInstanceOf(Class<?> type, T obj, String errorMsgTemplate, Object... params) {
        notNull(type, "Type to check against must not be null");
        if (!type.isInstance(obj)) {
            throw new ServiceException(StrUtil.format(errorMsgTemplate, params));
        }
    }

    /**
     * 断言 {@code superType.isAssignableFrom(subType)} 是否为 {@code true}.
     * @param superType 需要检查的父类或接口
     * @param subType   需要检查的子类
     */
    public static void isAssignable(Class<?> superType, Class<?> subType, String errorMsg) {
        isAssignable(superType, subType, errorMsg, subType, superType);
    }

    /**
     * 断言 {@code superType.isAssignableFrom(subType)} 是否为 {@code true}.
     * @param superType        需要检查的父类或接口
     * @param subType          需要检查的子类
     * @param errorMsgTemplate 异常时的消息模板
     * @param params           参数列表
     */
    public static void isAssignable(Class<?> superType, Class<?> subType, String errorMsgTemplate, Object... params) {
        notNull(superType, "Type to check against must not be null");
        if (subType == null || !superType.isAssignableFrom(subType)) {
            throw new ServiceException(StrUtil.format(errorMsgTemplate, params));
        }
    }

    /**
     * 断言两个对象是否不相等,如果两个对象相等 抛出异常
     * @param obj1             对象1
     * @param obj2             对象2
     * @param errorMsgTemplate 异常信息模板，类似于"aa{}bb{}cc"
     * @param params           异常信息参数，用于替换"{}"占位符
     */
    public static void notEquals(Object obj1, Object obj2, String errorMsgTemplate, Object... params) {
        notEquals(obj1, obj2, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言两个对象是否不相等,如果两个对象相等,抛出异常
     * @param obj1          对象1
     * @param obj2          对象2
     * @param errorMsg 错误抛出异常附带的消息
     */
    public static void notEquals(Object obj1, Object obj2, String errorMsg) {
        if (ObjectUtil.equals(obj1, obj2)) {
            throw new ServiceException(errorMsg);
        }
    }

    /**
     * 断言两个对象是否相等,如果两个对象不相等 抛出异常
     * @param obj1             对象1
     * @param obj2             对象2
     * @param errorMsgTemplate 异常信息模板，类似于"aa{}bb{}cc"
     * @param params           异常信息参数，用于替换"{}"占位符
     */
    public static void equals(Object obj1, Object obj2, String errorMsgTemplate, Object... params) {
        equals(obj1, obj2, StrUtil.format(errorMsgTemplate, params));
    }

    /**
     * 断言两个对象是否相等,如果两个对象不相等,抛出异常
     * @param obj1          对象1
     * @param obj2          对象2
     * @param errorMsg 错误抛出异常附带的消息
     */
    public static void equals(Object obj1, Object obj2, String errorMsg) {
        if (ObjectUtil.notEqual(obj1, obj2)) {
            throw new ServiceException(errorMsg);
        }
    }

}
